﻿
Imports spinlock = lock(Of locks.spinlock)

Friend Module share
    Public Class types_cache
        Public Shared ReadOnly defaultTypeName As String = Nothing
        Public Shared ReadOnly defaultTypeInstance As fromBytes = Nothing
        Private Shared t2nlock As spinlock
        Private Shared t2n As Dictionary(Of Type, String) = Nothing
        Private Shared n2tlock As spinlock
        Private Shared n2t As Dictionary(Of String, Type) = Nothing

        Shared Sub New()
            t2n = New Dictionary(Of Type, String)()
            n2t = New Dictionary(Of String, Type)()
            defaultTypeInstance = New bytesByte()
            assert([get](Of bytesByte)(defaultTypeName))
        End Sub

        Private Shared Sub add(ByVal t As Type, ByVal name As String)
            assert(Not t Is Nothing)
            assert(Not isemptystring(name))
            t2nlock.wait()
            t2n(t) = name
            t2nlock.release()
        End Sub

        Private Shared Sub add(ByVal name As String, ByVal t As Type)
            assert(Not t Is Nothing)
            assert(Not isemptystring(name))
            n2tlock.wait()
            n2t(name) = t
            n2tlock.release()
        End Sub

        Private Shared Function [get](ByVal t As Type, ByRef name As String) As Boolean
            assert(Not t Is Nothing)
            If Not t2n.TryGetValue(t, name) Then
                name = t.AssemblyQualifiedName()
                add(t, name)
            End If
            Return True
        End Function

        Public Shared Function [get](Of _T As toBytes)(ByRef name As String) As Boolean
            Return [get](GetType(_T), name)
        End Function

        Public Shared Function [get](ByVal i As toBytes, ByRef t As String) As Boolean
            If i Is Nothing Then
                Return False
            Else
                Return [get](i.GetType(), t)
            End If
        End Function

        Public Shared Function [get](ByVal name As String, ByRef o As fromBytes) As Boolean
            If isemptystring(name) Then
                Return False
            Else
                Dim t As Type = Nothing
                If Not n2t.TryGetValue(name, t) Then
                    t = Type.GetType(name, False)
                    If t Is Nothing Then
                        raiseError(errorHandle.errorType.warning, "failed to get type for name ", name)
                        Return False
                    End If
                    add(name, t)
                End If
                assert(Not t Is Nothing)
                o = alloc(t)
                If o Is Nothing Then
                    raiseError(errorHandle.errorType.warning, "failed to create instance for type ", name)
                    Return False
                Else
                    Return True
                End If
            End If
        End Function
    End Class
End Module

Public Module bytes_type
    Public Class type_pair
        Public ReadOnly first As Type = Nothing
        Public ReadOnly second As Type = Nothing

        Private Sub New(ByVal f As Type, ByVal s As Type)
            first = f
            second = s
        End Sub

        Public Shared Function create(Of T1, T2)() As type_pair
            Dim i As T2 = Nothing
            i = alloc(Of T2)()
            assert(Not i Is Nothing)
            assert(istype(Of bytesbase(Of T1))(i))
            Return New type_pair(GetType(T1), GetType(T2))
        End Function
    End Class

    Public ReadOnly bool_type As type_pair = Nothing
    Public ReadOnly bytes_type As type_pair = Nothing
    Public ReadOnly byte_type As type_pair = Nothing
    Public ReadOnly int16_type As type_pair = Nothing
    Public ReadOnly int32_type As type_pair = Nothing
    Public ReadOnly int64_type As type_pair = Nothing
    Public ReadOnly string_type As type_pair = Nothing
    Public ReadOnly types() As type_pair = Nothing
    Public ReadOnly types_count As Int64 = 0

    Public Class serializer_pair
        Public ReadOnly first As Type = Nothing
        Public ReadOnly second As serializer_d = Nothing

        Private Sub New(ByVal f As Type, ByVal s As serializer_d)
            first = f
            second = s
        End Sub

        Public Shared Function create(Of T)(ByVal s As serializer_d)
            assert(Not s Is Nothing)
            assert(istype(Of bytesbase(Of T))(s(Nothing)))
            Return New serializer_pair(GetType(T), s)
        End Function
    End Class

    Public Delegate Function serializer_d(ByVal i As Object) As toBytes
    Public ReadOnly bool_serializer As serializer_pair = Nothing
    Public ReadOnly bytes_serializer As serializer_pair = Nothing
    Public ReadOnly byte_serializer As serializer_pair = Nothing
    Public ReadOnly int16_serializer As serializer_pair = Nothing
    Public ReadOnly int32_serializer As serializer_pair = Nothing
    Public ReadOnly int64_serializer As serializer_pair = Nothing
    Public ReadOnly string_serializer As serializer_pair = Nothing
    Public ReadOnly serializers() As serializer_pair = Nothing
    Public ReadOnly serializers_count As Int64 = 0

    Public Class deserializer_pair
        Public ReadOnly first As Type = Nothing
        Public ReadOnly second As deserializer_d = Nothing

        Private Sub New(ByVal f As Type, ByVal s As deserializer_d)
            first = f
            second = s
        End Sub

        Public Shared Function create(Of T)(ByVal s As deserializer_d)
            assert(Not s Is Nothing)
            Return New deserializer_pair(GetType(T), s)
        End Function
    End Class

    Public Delegate Function deserializer_d(ByVal i As fromBytes) As Object
    Public ReadOnly bool_deserializer As deserializer_pair = Nothing
    Public ReadOnly bytes_deserializer As deserializer_pair = Nothing
    Public ReadOnly byte_deserializer As deserializer_pair = Nothing
    Public ReadOnly int16_deserializer As deserializer_pair = Nothing
    Public ReadOnly int32_deserializer As deserializer_pair = Nothing
    Public ReadOnly int64_deserializer As deserializer_pair = Nothing
    Public ReadOnly string_deserializer As deserializer_pair = Nothing
    Public ReadOnly deserializers() As deserializer_pair = Nothing
    Public ReadOnly deserializers_count As Int64 = 0

    Private Function c(Of T1, T2)(ByRef count As Int64) As type_pair
        Dim rtn As type_pair = Nothing
        rtn = type_pair.create(Of T1, T2)()
        types(inc_(count)) = rtn
        Return rtn
    End Function

    Private Function c(Of T)(ByVal s As serializer_d, ByRef count As Int64) As serializer_pair
        Dim rtn As serializer_pair = Nothing
        rtn = serializer_pair.create(Of T)(s)
        serializers(inc_(count)) = rtn
        Return rtn
    End Function

    Private Function c(Of T)(ByVal s As deserializer_d, ByRef count As Int64) As deserializer_pair
        Dim rtn As deserializer_pair = Nothing
        rtn = deserializer_pair.create(Of T)(s)
        deserializers(inc_(count)) = rtn
        Return rtn
    End Function

    Sub New()
        ReDim types(1023)
        Dim ct As Int64 = 0
        bool_type = c(Of Boolean, bytesBoolean)(ct)
        bytes_type = c(Of bytes, bytesbytes)(ct)
        byte_type = c(Of Byte, bytesByte)(ct)
        int16_type = c(Of Int16, bytesInt16)(ct)
        int32_type = c(Of Int32, bytesInt32)(ct)
        int64_type = c(Of Int64, bytesInt64)(ct)
        string_type = c(Of String, bytesString)(ct)
        ReDim Preserve types(ct - 1)
        types_count = ct

        ct = 0
        bool_serializer = c(Of Boolean)(Function(i) New bytesBoolean(i), ct)
        bytes_serializer = c(Of bytes)(Function(i) New bytesbytes(i), ct)
        byte_serializer = c(Of Byte)(Function(i) New bytesByte(i), ct)
        int16_serializer = c(Of Int16)(Function(i) New bytesInt16(i), ct)
        int32_serializer = c(Of Int32)(Function(i) New bytesInt32(i), ct)
        int64_serializer = c(Of Int64)(Function(i) New bytesInt64(i), ct)
        string_serializer = c(Of String)(Function(i) New bytesString(i), ct)
        ReDim Preserve serializers(ct - 1)
        serializers_count = ct

        ct = 0
        bool_deserializer = c(Of bytesBoolean)(Function(i) +convertor.cast(Of bytesBoolean)(i), ct)
        bytes_deserializer = c(Of bytesbytes)(Function(i) +convertor.cast(Of bytesbytes)(i), ct)
        byte_deserializer = c(Of bytesByte)(Function(i) +convertor.cast(Of bytesByte)(i), ct)
        int16_deserializer = c(Of bytesInt16)(Function(i) +convertor.cast(Of bytesInt16)(i), ct)
        int32_deserializer = c(Of bytesInt32)(Function(i) +convertor.cast(Of bytesInt32)(i), ct)
        int64_deserializer = c(Of bytesInt64)(Function(i) +convertor.cast(Of bytesInt64)(i), ct)
        string_deserializer = c(Of bytesString)(Function(i) +convertor.cast(Of bytesString)(i), ct)
        ReDim Preserve deserializers(ct - 1)
        deserializers_count = ct
    End Sub

    Public Function find_bytes_type(ByVal i As Type) As Type
        For j As Int64 = 0 To types_count - 1
            If i Is types(j).first Then
                Return types(j).second
            End If
        Next

        Return Nothing
    End Function

    Public Function find_serializer(ByVal i As Type) As serializer_d
        For j As Int64 = 0 To serializers_count - 1
            If i Is serializers(j).first Then
                Return serializers(j).second
            End If
        Next

        Return Nothing
    End Function

    Public Function find_deserializer(ByVal i As Type) As deserializer_d
        For j As Int64 = 0 To deserializers_count - 1
            If i Is deserializers(j).first Then
                Return deserializers(j).second
            End If
        Next

        Return Nothing
    End Function
End Module